<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>WAL 配置</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="SECT1">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="wal-intro.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="wal.html">快退</a></td><td width="60%" align="center" valign="bottom">章27. 可靠性和预写式日志</td><td width="10%" align="right" valign="top"><a href="wal.html">快进</a></td><td width="10%" align="right" valign="top"><a href="wal-internals.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<div class="SECT1"><h1 class="SECT1"><a name="WAL-CONFIGURATION">27.3. WAL 配置</a></h1>
<p>有几个与 WAL 相关的参数会影响数据库性能。本节讨论它们的使用。参阅<a href="runtime-config.html">章17</a>获取有关服务器配置参数的一般信息。</p>
<p><i class="FIRSTTERM">检查点</i>是事务序列中的点，在该点之前的所有信息都确保已经写到数据文件中去了。在检查点时，所有脏数据页都刷新到磁盘并且向日志文件中写入一条特殊的检查点记录。在发生崩溃的时候，崩溃恢复过程查找最后的检查点记录，判断应该从日志中的哪个点(称为 redo 记录)开始 REDO 操作，在该记录之前对数据文件的任何修改都被认为已经写在磁盘上了。因此，在检查点完成之后，任何在包含 redo 记录点之前的日志段都不再需要，因此可以循环使用或者删除。当然，在进行 WAL 归档的时候，这些日志在循环利用或者删除之前必须先归档。</p>
<p>服务器的后端写进程每 <a href="runtime-config-wal.html#GUC-CHECKPOINT-SEGMENTS">checkpoint_segments</a> 个日志段或每 <a href="runtime-config-wal.html#GUC-CHECKPOINT-TIMEOUT">checkpoint_timeout</a> 秒就创建一个检查点，以先到为准。缺省设置分别是 3 个段和 300 秒。我们也可以用 SQL 命令 <tt class="COMMAND">CHECKPOINT</tt> 强制创建一个检查点。</p>
<p>减少 <tt class="VARNAME">checkpoint_segments</tt> 和/或 <tt class="VARNAME">checkpoint_timeout</tt> 会更频繁的创建检查点。这样就允许更快的崩溃后恢复(因为需要重做的工作更少)。不过，我们必须在更快的恢复与更频繁的刷新脏数据页所带来的额外开销之间进行平衡。并且，如果开启了 <a href="runtime-config-wal.html#GUC-FULL-PAGE-WRITES">full_page_writes</a>(缺省开启)，那么还有其它的因素需要考虑。为了保证数据页的一致性，在每个检查点之后的第一次数据页变化会导致对整个页面内容的日志记录。因此，减小检查点时间间隔会导致输出到 WAL 日志中的数据量增加，从而抵销一部分缩短间隔的目标，并且无论如何都会产生更多的磁盘 I/O 操作。</p>
<p>检查点的开销相当高，首先是因为它需要写出所有当前脏缓冲区，其次是因为导致前面讨论过的额外后继 WAL 流量。因此把检查点参数设置得足够高，让检查点发生的频率降低是明智的。可以通过设置 <a href="runtime-config-wal.html#GUC-CHECKPOINT-WARNING">checkpoint_warning</a> 对检查点参数进行一个简单自检。如果检查点发生的间隔接近 <tt class="VARNAME">checkpoint_warning</tt> 秒，那么将向服务器日志输出一条消息，建议你增加 <tt class="VARNAME">checkpoint_segments</tt> 的数值。偶尔出现这样的警告并不会导致警报，但是如果出现得太频繁，那么就应该增加检查点控制参数。如果你没有把 <tt class="VARNAME">checkpoint_segments</tt> 设置得足够大，那么批量操作的时候(比如大批的 <tt class="COMMAND">COPY</tt> 传输)会导致出现大量此类警告消息。</p>
<p>至少会有一个 WAL 段文件，而且通常不会超过 2*<tt class="VARNAME">checkpoint_segments</tt>+1 个文件。每个段文件通常为 16MB(你可以在编译服务器的时候修改它)。你可以用这些信息来估计 WAL 需要的空间。通常，如果一个旧日志段文件不再需要了，那么它将得到循环使用(重命名为顺序的下一个可用段)。如果由于短期的日志输出高峰导致了超过 2*<tt class="VARNAME">checkpoint_segments</tt>+1 个段文件，那么当系统再次回到这个限制之内的时候，多余的段文件将被删除，而不是循环使用。</p>
<p>有两个常用的内部 WAL 函数 <code class="FUNCTION">LogInsert</code> 和 <code class="FUNCTION">LogFlush</code> 。<code class="FUNCTION">LogInsert</code> 用于向共享内存中的 WAL 缓冲区里添加一条新记录。如果没有空间存放新记录，那么 <code class="FUNCTION">LogInsert</code> 就不得不写出(向内核缓存里写)一些填满了的 WAL 缓冲。我们可不想这样，因为 <code class="FUNCTION">LogInsert</code> 用于每次数据库低层修改(比如插入记录)时都要在受影响的数据页上持有一个排它锁，因为该操作需要越快越好；更糟糕的是，写 WAL 缓冲可能还会强制创建新的日志段，它花的时间甚至更多。通常，WAL 缓冲区应该由一个 <code class="FUNCTION">LogFlush</code> 请求来写和刷新，在大部分时候它都是发生在事务提交的时候以确保事务记录被刷新到永久存储器上去了。在那些日志输入量比较大的系统上，<code class="FUNCTION">LogFlush</code> 请求可能不够频繁，这样就不能避免 <code class="FUNCTION">LogInsert</code> 进行写操作。在这样的系统上，我们应该提高配置参数 <a href="runtime-config-wal.html#GUC-WAL-BUFFERS">wal_buffers</a> 的值(缺省为 8)来增加 WAL 缓冲区的数量。增加这个数值将造成共享内存使用量的增加。如果设置了 <a href="runtime-config-wal.html#GUC-FULL-PAGE-WRITES">full_page_writes</a> 并且系统相当繁忙，把这个数值设置得高一些将有助于在紧随每个检查点之后的时间里平滑响应时间。</p>
<p><a href="runtime-config-wal.html#GUC-COMMIT-DELAY">commit_delay</a> 定义了后端在使用 <code class="FUNCTION">LogInsert</code> 向日志中写了一条已提交的记录之后，再执行一次 <code class="FUNCTION">LogFlush</code> 之前休眠的毫秒数。这样的延迟可以允许其它的后端把它们提交的记录追加到日志中，这样就可以用一次日志同步把所有日志刷新到日志中。如果没有打开 <a href="runtime-config-wal.html#GUC-FSYNC">fsync</a> 或者当前少于 <a href="runtime-config-wal.html#GUC-COMMIT-SIBLINGS">commit_siblings</a> 个处于活跃事务状态的其它后端时则不会发生休眠；这样就避免了在其它事务不会很快提交的情况下睡眠。请注意，在大多数平台上，休眠要求的分辩率是 10 毫秒，所以任何介于 1 和 10000 微秒之间的非零 <tt class="VARNAME">commit_delay</tt> 的作用都是一样的。适用这些参数的比较好的数值还不太清楚；我们鼓励你多做试验。</p>
<p><a href="runtime-config-wal.html#GUC-WAL-SYNC-METHOD">wal_sync_method</a> 参数决定 PostgreSQL 如何请求操作系统内核强制将 WAL 更新输出到磁盘。只要满足可靠性，那么所有选项应该都是一样的，但是哪个最快则可能和平台密切相关。请注意如果你关闭了 <tt class="VARNAME">fsync</tt> 的话这个参数就无关紧要了。</p>
<p>打开 <a href="runtime-config-developer.html#GUC-WAL-DEBUG">wal_debug</a> 配置参数(前提是编译 PostgreSQL 的时候打开了这个支持)将导致每次 <code class="FUNCTION">LogInsert</code> 和 <code class="FUNCTION">LogFlush</code> WAL 调用都被记录到服务器日志。这个选项以后可能会被更通用的机制取代。</p>
</div>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="wal-intro.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="wal-internals.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top">预写式日志(WAL)</td><td width="34%" align="center" valign="top"><a href="wal.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">WAL 内部</td></tr>
</table>
</div>
</body></html>